package agents;

import java.util.ArrayList;

import aglobe.container.agent.Agent;
import aglobe.container.transport.InvisibleContainerException;
import aglobe.ontology.AgentInfo;
import aglobe.ontology.Message;
import aglobe.ontology.MessageConstants;
import model.Model;
import model.Model.Directions;
import model.info.Constants;
import model.mapping.MapPoint;
import model.simulation.Point3D;

public class PointRouteAgent extends Agent {
	
	private Model model;
	private ArrayList<Point3D> inNorth;
	private ArrayList<Point3D> inSouth;
	private ArrayList<Point3D> inEast;
	private ArrayList<Point3D> inWest;
	private ArrayList<Point3D> outNorth;
	private ArrayList<Point3D> outSouth;
	private ArrayList<Point3D> outEast;
	private ArrayList<Point3D> outWest;
	private Integer selectedPoint;

	public void init(AgentInfo info, int initState) {
		
		selectedPoint = 0;
		inNorth = new ArrayList<Point3D>();
		inSouth = new ArrayList<Point3D>();
		inEast = new ArrayList<Point3D>();
		inWest = new ArrayList<Point3D>();
		outNorth = new ArrayList<Point3D>();
		outSouth = new ArrayList<Point3D>();
		outEast = new ArrayList<Point3D>();
		outWest = new ArrayList<Point3D>();
	}
	

	public void handleIncomingMessage(Message message) {
	
		if (message.getPerformative().equals(MessageConstants.INFORM)) {
			if (message.getContent() instanceof String) 
				if (message.getContent().equals(Constants.KILL))
					finishExecution();
		}
	}
	
	public ArrayList<Point3D> getInNorth() {
		return inNorth;
	}

	public void setInNorth(ArrayList<Point3D> north) {
		this.inNorth = north;
	}

	public ArrayList<Point3D> getInSouth() {
		return inSouth;
	}

	public void setInSouth(ArrayList<Point3D> south) {
		this.inSouth = south;
	}

	public ArrayList<Point3D> getInEast() {
		return inEast;
	}

	public void setInEast(ArrayList<Point3D> east) {
		this.inEast = east;
	}
	
	public ArrayList<Point3D> getInWest() {
		return inWest;
	}

	public void setInWest(ArrayList<Point3D> west) {
		this.inWest = west;
	}

	public ArrayList<Point3D> getOutNorth() {
		return outNorth;
	}

	public void setOutNorth(ArrayList<Point3D> outNorth) {
		this.outNorth = outNorth;
	}

	public ArrayList<Point3D> getOutSouth() {
		return outSouth;
	}

	public void setOutSouth(ArrayList<Point3D> outSouth) {
		this.outSouth = outSouth;
	}

	public ArrayList<Point3D> getOutEast() {
		return outEast;
	}

	public void setOutEast(ArrayList<Point3D> outEast) {
		this.outEast = outEast;
	}

	public ArrayList<Point3D> getOutWest() {
		return outWest;
	}

	public void setOutWest(ArrayList<Point3D> outWest) {
		this.outWest = outWest;
	}

	public Integer getSelectedPoint() {
		return selectedPoint;
	}

	public void setSelectedPoint(Integer selectedPoint) {
		this.selectedPoint = selectedPoint;
	}
	
	public void execPointRouteAgent(Model model) {
		
		this.model = model;
		getInPoints();
		getOutPoints();
		sendPointsCalculated();
	}
	
	public void sendPointsCalculated() {
		
		Message message = Message.newInstance();
		message.setPerformative(MessageConstants.INFORM);
		message.setSender(getAddress());
		message.setReceiver(model.getTrafficAgent().getAddress());
		message.setContent(Constants.POINTS_CALCULATED);
		try {
			sendMessage(message);
		} catch (InvisibleContainerException e) {
			e.printStackTrace();
		}
	}
	
	/*public Point3D getNewInPoint(ArrayList<Point3D> currentPoints) {
		
		if (selectedPoint >= currentPoints.size()) {
			selectedPoint = 0;
			if (currentPoints == inNorth)
				currentPoints = inSouth;
			else if (currentPoints == inSouth)
				currentPoints = inWest;
			else if (currentPoints == inWest)
				currentPoints = inEast;
			else if (currentPoints == inEast)
				currentPoints = inNorth;
		}
		Point3D point = currentPoints.get(selectedPoint);
		selectedPoint = selectedPoint + 1;
		return point;
	}*/
	
	public void getInPoints() {
		
		MapPoint[][] map = model.getModelMapBuilder().getDriverMap();
		for (int i=0;i<model.getMapPanel().getWidth();i++) {
			Boolean found = false;
			for (int p=0;p<map[i][0].getDataList().size()&&!found;p++) {
				if (map[i][0].isRoad() && model.getMapCheckouts().isVehicleWay(i,0,p) &&
						map[i][0].getDataList().get(p).getLaneNumber().intValue() == 1 &&
						testDirection(i,0,p,Directions.UP.ordinal()) &&
						testDirection(i,0,p,Directions.RIGHTUP.ordinal()) &&
						testDirection(i,0,p,Directions.LEFTUP.ordinal()))  {
							found = true;
							Point3D punto = new Point3D(i,0,p,Model.Cardinals.NORTH.ordinal());
							if (!inNorth.contains(punto)) 
								inNorth.add(punto);
				}
			}
		}	
			
		for (int i=0;i<model.getMapPanel().getWidth();i++) {
			Boolean found = false;
			for (int p=0;p<model.getModelMapBuilder().getDriverMap()[i][model.getMapPanel().getHeight()-1].getDataList().size()&&!found;p++) {
				if (map[i][model.getMapPanel().getHeight()-1].isRoad() &&
						model.getMapCheckouts().isVehicleWay(i,model.getMapPanel().getHeight()-1,p) &&
						map[i][model.getMapPanel().getHeight()-1].getDataList().get(p).getLaneNumber().intValue() == 1 &&
						testDirection(i,model.getMapPanel().getHeight()-1,p,Directions.DOWN.ordinal()) &&
						testDirection(i,model.getMapPanel().getHeight()-1,p,Directions.RIGHTDOWN.ordinal()) && 
						testDirection(i,model.getMapPanel().getHeight()-1,p,Directions.LEFTDOWN.ordinal())) {
							found = true;	
							Point3D punto = new Point3D(i,model.getMapPanel().getHeight()-1,
								p,Model.Cardinals.SOUTH.ordinal());
							if (!inSouth.contains(punto)) 
								inSouth.add(punto);
				}
			}
		}

		for (int j=0;j<model.getMapPanel().getHeight();j++) {
			Boolean found = false;
			for (int p=0;p<model.getModelMapBuilder().getDriverMap()[0][j].getDataList().size()&&!found;p++) {
				if (map[0][j].isRoad() && model.getMapCheckouts().isVehicleWay(0,j,p) &&
						map[0][j].getDataList().get(p).getLaneNumber().intValue() == 1 &&
						testDirection(0,j,p,Directions.LEFT.ordinal()) && 
						testDirection(0,j,p,Directions.LEFTUP.ordinal()) &&
						testDirection(0,j,p,Directions.LEFTDOWN.ordinal())) {
							found = true;
							Point3D punto = new Point3D(0,j,p,Model.Cardinals.WEST.ordinal());
							if (!inWest.contains(punto)) 
								inWest.add(punto);
					}
			}
		}	
		
		for (int j=0;j<model.getMapPanel().getHeight();j++) {
			Boolean found = false;
			for (int p=0;p<model.getModelMapBuilder().getDriverMap()[model.getMapPanel().getWidth()-1][j].getDataList().size()&&!found;p++) {
				if (map[model.getMapPanel().getWidth()-1][j].isRoad() &&
						model.getMapCheckouts().isVehicleWay(model.getMapPanel().getWidth()-1,j,p) &&
						map[model.getMapPanel().getWidth()-1][j].getDataList().get(p).getLaneNumber().intValue() == 1 &&
						testDirection(model.getMapPanel().getWidth()-1,j,p,Directions.RIGHT.ordinal()) &&
						testDirection(model.getMapPanel().getWidth()-1,j,p,Directions.RIGHTUP.ordinal()) &&
						testDirection(model.getMapPanel().getWidth()-1,j,p,Directions.RIGHTDOWN.ordinal())) {
							found = true;
							Point3D punto = new Point3D(model.getMapPanel().getWidth()-1,j,
								p,Model.Cardinals.EAST.ordinal());
							if (!inEast.contains(punto)) 
									inEast.add(punto);
				}
			}
		}	
	}
	
	public void getOutPoints() {
		
		MapPoint[][] mapa = model.getModelMapBuilder().getDriverMap();
		for (int i=0;i<model.getMapPanel().getWidth();i++) {
			Boolean found = false;
			for (int p=0;p<model.getModelMapBuilder().getDriverMap()[i][0].getDataList().size()&&!found;p++) {
				if (mapa[i][0].isRoad() && model.getMapCheckouts().isVehicleWay(i,0,p) &&
						testDirection(i,0,p,Directions.DOWN.ordinal()) &&
						testDirection(i,0,p,Directions.RIGHTDOWN.ordinal()) &&
						testDirection(i,0,p,Directions.LEFTDOWN.ordinal()))  {
							found = true;
							Point3D punto = new Point3D(i,0,p,Model.Cardinals.NORTH.ordinal());
							if (!outNorth.contains(punto)) 
								outNorth.add(punto);
				}
			}
		}	
			
		for (int i=0;i<model.getMapPanel().getWidth();i++) {
			Boolean found = false;
			for (int p=0;p<model.getModelMapBuilder().getDriverMap()[i][model.getMapPanel().getHeight()-1].getDataList().size()&&!found;p++) {
				if (mapa[i][model.getMapPanel().getHeight()-1].isRoad() &&
						model.getMapCheckouts().isVehicleWay(i,model.getMapPanel().getHeight()-1,p) &&
						testDirection(i,model.getMapPanel().getHeight()-1,p,Directions.UP.ordinal()) &&
						testDirection(i,model.getMapPanel().getHeight()-1,p,Directions.RIGHTUP.ordinal()) && 
						testDirection(i,model.getMapPanel().getHeight()-1,p,Directions.LEFTUP.ordinal())) {
							found = true;	
							Point3D punto = new Point3D(i,model.getMapPanel().getHeight()-1,
								p,Model.Cardinals.SOUTH.ordinal());
							if (!outSouth.contains(punto)) 
								outSouth.add(punto);
				}
			}
		}

		for (int j=0;j<model.getMapPanel().getHeight();j++) {
			Boolean found = false;
			for (int p=0;p<model.getModelMapBuilder().getDriverMap()[0][j].getDataList().size()&&!found;p++) {
				if (mapa[0][j].isRoad() && model.getMapCheckouts().isVehicleWay(0,j,p) &&
						testDirection(0,j,p,Directions.RIGHT.ordinal()) &&
						testDirection(0,j,p,Directions.RIGHTUP.ordinal()) &&
						testDirection(0,j,p,Directions.LEFTUP.ordinal())) {
							found = true;
							Point3D punto = new Point3D(0,j,p,Model.Cardinals.WEST.ordinal());
							if (!outWest.contains(punto)) 
								outWest.add(punto);
					}
			}
		}	
		
		for (int j=0;j<model.getMapPanel().getHeight();j++) {
			Boolean found = false;
			for (int p=0;p<model.getModelMapBuilder().getDriverMap()[model.getMapPanel().getWidth()-1][j].getDataList().size()&&!found;p++) {
				if (mapa[model.getMapPanel().getWidth()-1][j].isRoad() &&
						model.getMapCheckouts().isVehicleWay(model.getMapPanel().getWidth()-1,j,p) &&
						testDirection(model.getMapPanel().getWidth()-1,j,p,Directions.LEFT.ordinal()) &&
						testDirection(model.getMapPanel().getWidth()-1,j,p,Directions.LEFTUP.ordinal()) &&
						testDirection(model.getMapPanel().getWidth()-1,j,p,Directions.LEFTDOWN.ordinal())) {
							found = true;
							Point3D point = new Point3D(model.getMapPanel().getWidth()-1,j,
								p,Model.Cardinals.EAST.ordinal());
							if (!outEast.contains(point)) 
									outEast.add(point);
				}
			}
		}	
	}
	
	public Boolean testDirection(int x,int y,int p,Integer value) {
		
		Boolean correct = false;
		if (model.getModelMapBuilder().getDriverMap()[x][y].isRoad()) {
			if (!model.getModelMapBuilder().getDriverMap()[x][y].getDataList().get(p).getDirection().equals(value)) 
				correct = true;
		}
		return correct;
	}

	public void finishExecution() {
		
		try {
			System.out.println("Generador de puntos muerto");
			kill();
			finish();
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}
}
